package net.simflow.swf.analyzer.gui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.Vector;

import net.simflow.swf.analyzer.bgnetwork.data.BGNode;
import net.simflow.swf.analyzer.data.DataPkg;
import net.simflow.swf.analyzer.exec.stats.data.FlowExecTime;
import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Service;

import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.wb.swt.SWTResourceManager;

public class ServiceInfluenceDialog extends Dialog {

	protected Object result;
	protected Shell shlServiceInfluences;
	private Text txtResult;
	private Table tblService;
	private DataPkg dataPkg;
	private Button btnAnalyze;
	private TableColumn tblclmnSchedule;
	private TableViewerColumn tableViewerSchedule;
	private TableColumn tblclmnAbility;
	private TableViewerColumn tableViewerAbility;

	/**
	 * Create the dialog.
	 * 
	 * @param parent
	 * @param style
	 */
	public ServiceInfluenceDialog(Shell parent, int style, DataPkg dataPkg) {
		super(parent, style);
		setText("SWT Dialog");

		this.dataPkg = dataPkg;
	}

	/**
	 * Open the dialog.
	 * 
	 * @return the result
	 */
	public Object open() {
		createContents();
		shlServiceInfluences.open();
		shlServiceInfluences.layout();

		initServices();

		Display display = getParent().getDisplay();
		while (!shlServiceInfluences.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		return result;
	}

	private void initServices() {
		if (this.dataPkg == null) {
			return;
		}

		TreeSet<String> set = new TreeSet<String>(dataPkg.getNetworkPkg()
				.getNetwork().getServiceMap().keySet());
		set.comparator();
		for (String name : set) {
			Service svc = dataPkg.getNetworkPkg().getNetwork().getServiceMap()
					.get(name);
			int schedule = this.dataPkg.getNetworkExecResultPkg()
					.getExecResult().getServiceScheduleMap().get(svc);
			int ability = this.dataPkg.getNetworkExecResultPkg()
					.getExecResult().getServiceAbilityMap().get(svc);

			TableItem item = new TableItem(this.tblService, SWT.NONE);
			item.setText(new String[] { name, String.valueOf(schedule),
					String.valueOf(ability) });
			if (schedule != 0) {
				item.setChecked(true);
			}
		}

		tblService.getColumn(0).pack();
		tblService.getColumn(1).pack();
		tblService.getColumn(2).pack();
	}

	/**
	 * Create contents of the dialog.
	 */
	private void createContents() {
		shlServiceInfluences = new Shell(getParent(), SWT.SHELL_TRIM
				| SWT.BORDER);
		shlServiceInfluences.setSize(825, 616);
		shlServiceInfluences.setText("Service Influences");
		shlServiceInfluences.setLayout(new GridLayout(2, false));

		CheckboxTableViewer checkboxTableViewerService = CheckboxTableViewer
				.newCheckList(shlServiceInfluences, SWT.BORDER
						| SWT.FULL_SELECTION);
		tblService = checkboxTableViewerService.getTable();
		tblService.setLinesVisible(true);
		tblService.setHeaderVisible(true);
		GridData gd_tblService = new GridData(SWT.FILL, SWT.FILL, false, true,
				1, 1);
		gd_tblService.widthHint = 253;
		tblService.setLayoutData(gd_tblService);

		TableViewerColumn tableViewerService = new TableViewerColumn(
				checkboxTableViewerService, SWT.NONE);
		TableColumn tblclmnService = tableViewerService.getColumn();
		tblclmnService.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				switch (tblService.getSortDirection()) {
				case SWT.UP:
					sortTable(tblService, 0, SWT.DOWN);
					break;
				case SWT.DOWN:
					sortTable(tblService, 0, SWT.UP);
					break;
				default:
					sortTable(tblService, 0, SWT.UP);
				}
			}
		});
		tblclmnService.setText("Service");
		tblclmnService.setWidth(120);

		tableViewerSchedule = new TableViewerColumn(checkboxTableViewerService,
				SWT.NONE);
		tblclmnSchedule = tableViewerSchedule.getColumn();
		tblclmnSchedule.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				switch (tblService.getSortDirection()) {
				case SWT.UP:
					sortTable(tblService, 1, SWT.DOWN);
					break;
				case SWT.DOWN:
					sortTable(tblService, 1, SWT.UP);
					break;
				default:
					sortTable(tblService, 1, SWT.UP);
				}
			}
		});
		tblclmnSchedule.setAlignment(SWT.RIGHT);
		tblclmnSchedule.setWidth(50);
		tblclmnSchedule.setText("Schedule");

		tableViewerAbility = new TableViewerColumn(checkboxTableViewerService,
				SWT.NONE);
		tblclmnAbility = tableViewerAbility.getColumn();
		tblclmnAbility.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				switch (tblService.getSortDirection()) {
				case SWT.UP:
					sortTable(tblService, 2, SWT.DOWN);
					break;
				case SWT.DOWN:
					sortTable(tblService, 2, SWT.UP);
					break;
				default:
					sortTable(tblService, 2, SWT.UP);
				}
			}
		});
		tblclmnAbility.setAlignment(SWT.RIGHT);
		tblclmnAbility.setWidth(50);
		tblclmnAbility.setText("Ability");

		txtResult = new Text(shlServiceInfluences, SWT.BORDER | SWT.READ_ONLY
				| SWT.V_SCROLL | SWT.MULTI);
		txtResult.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		txtResult.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1,
				2));

		btnAnalyze = new Button(shlServiceInfluences, SWT.NONE);
		btnAnalyze.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				txtResult.setText("");
				analyzeFlow();
				analyzeService();
			}
		});
		btnAnalyze.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnAnalyze.setText("Analyze");

	}

	private void sortTable(final Table table, final int column, final int order) {
		ArrayList<Vector<String>> l = new ArrayList<Vector<String>>();
		HashMap<Vector<String>, Boolean> map = new HashMap<Vector<String>, Boolean>();
		for (TableItem item : table.getItems()) {
			Vector<String> v = new Vector<String>();
			for (int i = 0; i < table.getColumnCount(); i++) {
				v.add(item.getText(i));
			}
			l.add(v);
			map.put(v, item.getChecked());
		}
		Collections.sort(l, new Comparator<Vector<String>>() {
			public int compare(Vector<String> o1, Vector<String> o2) {
				int com;
				try {
					com = Double.valueOf(o1.get(column)).compareTo(
							Double.valueOf(o2.get(column)));
				} catch (Exception e) {
					com = (o1.get(column).compareToIgnoreCase(o2.get(column)));
				}
				switch (order) {
				case SWT.UP:
					return com;
				case SWT.DOWN:
					return -com;
				default:
					return 0;
				}
			}
		});

		table.removeAll();
		for (Vector<String> v : l) {
			TableItem item = new TableItem(table, SWT.NONE);
			String[] a = new String[v.size()];
			v.toArray(a);
			item.setText(a);
			item.setChecked(map.get(v));
		}

		table.setSortColumn(table.getColumn(column));
		table.setSortDirection(order);
	}

	private void analyzeFlow() {
		StringBuffer str = new StringBuffer();

		int c;
		HashSet<Service> sSet = new HashSet<Service>();
		TreeSet<String> allSet = new TreeSet<String>();
		TreeSet<String> lSet = new TreeSet<String>();

		for (TableItem item : tblService.getItems()) {
			if (item.getChecked()) {
				sSet.add(dataPkg.getNetworkPkg().getNetwork().getServiceMap()
						.get(item.getText(0)));
			}
		}

		for (Service svc : sSet) {
			HashSet<BGNode> set = dataPkg.getNetworkPkg().getBgNetwork()
					.getServiceMap().get(svc).getNeighborSet();
			for (BGNode node : set) {
				lSet.add(node.getFlow().getNameInNetwork());
			}
		}

		c = 0;
		while (!lSet.isEmpty()) {
			lSet.comparator();
			str.append("Distance ").append(c).append(":\n");
			for (String fN : lSet) {
				Flow f = dataPkg.getNetworkPkg().getNetwork().getFlowMap()
						.get(fN);
				FlowExecTime et = dataPkg.getNetworkExecResultPkg()
						.getExecStats().getFlowExecTimeMap().get(f);
				str.append(f.getNameInNetwork());
				str.append("\t").append(et.getMaxTime());
				str.append("\t").append(et.getMinTime());
				str.append("\t").append(et.getAvgTime());
				str.append("\n");
			}
			str.append("\n\n");

			allSet.addAll(lSet);

			TreeSet<String> temp = new TreeSet<String>();
			for (String fN : lSet) {
				Flow f = dataPkg.getNetworkPkg().getNetwork().getFlowMap()
						.get(fN);
				HashSet<BGNode> set = dataPkg.getNetworkPkg().getBgFlowMap()
						.get(f).getNeighborSet();
				for (BGNode node : set) {
					temp.add(node.getFlow().getNameInNetwork());
				}
			}
			temp.removeAll(allSet);

			lSet = temp;
			c++;
		}

		allSet.comparator();
		str.append("All:\n");
		for (String fN : allSet) {
			Flow f = dataPkg.getNetworkPkg().getNetwork().getFlowMap().get(fN);
			FlowExecTime et = dataPkg.getNetworkExecResultPkg().getExecStats()
					.getFlowExecTimeMap().get(f);
			str.append(f.getNameInNetwork());
			str.append("\t").append(et.getMaxTime());
			str.append("\t").append(et.getMinTime());
			str.append("\t").append(et.getAvgTime());
			str.append("\n");
		}
		str.append("\n\n");

		txtResult.append(str.toString());
	}

	private void analyzeService() {
		StringBuffer str = new StringBuffer();

		int c;
		TreeSet<String> allSet = new TreeSet<String>();
		TreeSet<String> lSet = new TreeSet<String>();

		for (TableItem item : tblService.getItems()) {
			if (item.getChecked()) {
				lSet.add(item.getText(0));
			}
		}

		c = 0;
		while (!lSet.isEmpty()) {
			str.append("Distance ").append(c).append(":\n");
			for (String sN : lSet) {
				Service s = dataPkg.getNetworkPkg().getNetwork()
						.getServiceMap().get(sN);
				str.append(s.getNameInNetwork());
				str.append("\t").append(s.getMaxWaitTime());
				str.append("\t").append(s.getMinWaitTime());
				str.append("\t").append(s.getAvgWatiTime());
				str.append("\n");
			}
			str.append("\n\n");

			allSet.addAll(lSet);

			TreeSet<String> temp = new TreeSet<String>();
			for (String sN : lSet) {
				Service s = dataPkg.getNetworkPkg().getNetwork()
						.getServiceMap().get(sN);
				HashSet<BGNode> set = dataPkg.getNetworkPkg().getBgServiceMap()
						.get(s).getNeighborSet();
				for (BGNode node : set) {
					temp.add(node.getService().getNameInNetwork());
				}
			}
			temp.removeAll(allSet);

			lSet = temp;
			c++;
		}

		str.append("All:\n");
		for (String sN : allSet) {
			Service s = dataPkg.getNetworkPkg().getNetwork().getServiceMap()
					.get(sN);
			str.append(s.getNameInNetwork());
			str.append("\t").append(s.getMaxWaitTime());
			str.append("\t").append(s.getMinWaitTime());
			str.append("\t").append(s.getAvgWatiTime());
			str.append("\n");
		}
		str.append("\n\n");

		txtResult.append(str.toString());
	}
}
